import {
  CanActivate,
  ExecutionContext,
  ForbiddenException,
  Injectable,
} from '@nestjs/common';
import { isUUID } from 'class-validator';
import * as crypto from 'crypto';
import dayjs from 'dayjs';

const appMap = {
  '76a8f4cf-2781-4085-b2d1-d15cc88b5642': 'e079288d-76b6-4813-9d32-fe997f057373',
};

@Injectable()
export class OpenApiAuthGuard implements CanActivate {
  static expireSecond = 5 * 60; // 5分钟

  constructor(
  ) {
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const appKey: string = request.headers['appkey'];
    if (!isUUID(appKey)) {
      throw new ForbiddenException('appkey必须为uuid。appkey must be uuid');
    }
    if(!(appKey in appMap)){
      throw new ForbiddenException('appkey不存在。appkey not exists');
    }
    const sign: string = request.headers['sign'];
    if (!sign) {
      throw new ForbiddenException(
        'header中的sign必须存在。header sign must be exists',
      );
    }
    const timestamp: string = request.headers['timestamp'];
    if (!timestamp) {
      throw new ForbiddenException(
        'header中的timestamp必须存在。header timestamp must be exists',
      );
    }
    const minuteDiff = dayjs(Number(timestamp)).diff(dayjs(), 'seconds', true);
    if (
      minuteDiff > OpenApiAuthGuard.expireSecond ||
      minuteDiff < -OpenApiAuthGuard.expireSecond
    ) {
      throw new ForbiddenException(
        `header中的timestamp必须在${OpenApiAuthGuard.expireSecond}秒之内。header timestamp must within ${OpenApiAuthGuard.expireSecond} seconds`,
      );
    }

    const signStr = appKey + timestamp;

    const mySign = crypto
      .createHmac('sha256', appMap[appKey as keyof typeof appMap])
      .update(signStr)
      .digest('base64');

    if (sign !== mySign) {
      throw new ForbiddenException(
        'header中的sign不正确。header sign is error',
      );
    }

    return true;
  }
}
